home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3.2 / Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO / packet / n17jsrc / pppipcp.c < prev    next >
C/C++ Source or Header  |  1991-06-07  |  29KB  |  1,121 lines

  1. /*
  2.  *  PPPIPCP.C    -- negotiate IP parameters
  3.  *
  4.  *    This implementation of PPP is declared to be in the public domain.
  5.  *
  6.  *    Jan 91    Bill_Simpson@um.cc.umich.edu
  7.  *        Computer Systems Consulting Services
  8.  *
  9.  *    Acknowledgements and correction history may be found in PPP.C
  10.  */
  11.  
  12. #include <stdio.h>
  13. #include <ctype.h>
  14. #include <time.h>
  15. #include "global.h"
  16. #include "mbuf.h"
  17. #include "iface.h"
  18. #include "slhc.h"
  19. #include "ppp.h"
  20. #include "pppfsm.h"
  21. #include "pppipcp.h"
  22. #include "ppplcp.h"
  23. #include "ppppap.h"
  24. #include "cmdparse.h"
  25. #include "files.h"
  26.  
  27.  
  28. /* These defaults are defined in the PPP RFCs, and must not be changed */
  29. static struct ipcp_value_s ipcp_default = {
  30.     FALSE,            /* no need to negotiate defaults */
  31.  
  32.     0L,            /* no source address */
  33.     0L,            /* no destination address */
  34.  
  35.     0,            /* no compression protocol */
  36.     0,            /* no slots */
  37.     0            /* no slot compression */
  38. };
  39.  
  40. /* for test purposes, accept anything we understand */
  41. static int16 ipcp_negotiate = IPCP_N_ADDRESS | IPCP_N_COMPRESS;
  42.  
  43. static byte_t option_length[] = {
  44.      0,        /* unused */
  45.     10,        /* address */
  46.      6        /* compression */
  47. };
  48.  
  49.  
  50. static int doipcp_local        __ARGS((int argc, char *argv[], void *p));
  51. static int doipcp_open        __ARGS((int argc, char *argv[], void *p));
  52. static int doipcp_pool        __ARGS((int argc, char *argv[], void *p));
  53. static int doipcp_remote    __ARGS((int argc, char *argv[], void *p));
  54.  
  55. static int doipcp_address    __ARGS((int argc, char *argv[], void *p));
  56. static int doipcp_compress    __ARGS((int argc, char *argv[], void *p));
  57. static int doipcp_default    __ARGS((int argc, char *argv[], void *p));
  58.  
  59. static void ipcp_option __ARGS((struct mbuf **bpp,
  60.             struct ipcp_value_s *value_p,
  61.             byte_t o_type,
  62.             byte_t o_length,
  63.             struct mbuf **copy_bpp));
  64. static void ipcp_makeoptions __ARGS((struct mbuf **bpp,
  65.             struct ipcp_value_s *value_p,
  66.             int16 negotiating));
  67. static struct mbuf *ipcp_makereq __ARGS((struct fsm_s *fsm_p));
  68.  
  69. static int ipcp_check __ARGS((struct mbuf **bpp,
  70.             struct ipcp_s *ipcp_p,
  71.             struct ipcp_side_s *side_p,
  72.             struct option_hdr *option_p,
  73.             int request));
  74.  
  75. static int ipcp_request    __ARGS((struct fsm_s *fsm_p,
  76.             struct config_hdr *config,
  77.             struct mbuf *data));
  78. static int ipcp_ack    __ARGS((struct fsm_s *fsm_p,
  79.             struct config_hdr *config,
  80.             struct mbuf *data));
  81. static int ipcp_nak    __ARGS((struct fsm_s *fsm_p,
  82.             struct config_hdr *config,
  83.             struct mbuf *data));
  84. static int ipcp_reject    __ARGS((struct fsm_s *fsm_p,
  85.             struct config_hdr *config,
  86.             struct mbuf *data));
  87.  
  88. static void ipcp_reset    __ARGS((struct fsm_s *fsm_p));
  89.  
  90. static int32 ipcp_addr_idle __ARGS((int32 addr));
  91. static int32 ipcp_lookuppeer __ARGS((char *peerid));
  92. static int32 ipcp_poolnext __ARGS((struct ipcp_s *ipcp_p));
  93.  
  94. static void ipcp_starting __ARGS((struct fsm_s *fsm_p));
  95. static void ipcp_stopping __ARGS((struct fsm_s *fsm_p));
  96.  
  97. static void ipcp_closing __ARGS((struct fsm_s *fsm_p));
  98. static void ipcp_opening __ARGS((struct fsm_s *fsm_p));
  99.  
  100. static void ipcp_free    __ARGS((struct fsm_s *fsm_p));
  101. static void ipcp_init    __ARGS((struct ppp_s *ppp_p));
  102.  
  103.  
  104. static struct fsm_constant_s ipcp_constants = {
  105.     "IPcp",
  106.     PPP_IPCP_PROTOCOL,
  107.     0x00FE,                /* codes 1-7 recognized */
  108.  
  109.     IPcp,
  110.     IPCP_REQ_TRY,
  111.     IPCP_NAK_TRY,
  112.     IPCP_TERM_TRY,
  113.     IPCP_TIMEOUT * 1000L,
  114.  
  115.     ipcp_free,
  116.  
  117.     ipcp_reset,
  118.     ipcp_starting,
  119.     ipcp_opening,
  120.     ipcp_closing,
  121.     ipcp_stopping,
  122.  
  123.     ipcp_makereq,
  124.     ipcp_request,
  125.     ipcp_ack,
  126.     ipcp_nak,
  127.     ipcp_reject,
  128. };
  129.  
  130.  
  131. /************************************************************************/
  132.  
  133. /* "ppp <iface> ipcp" subcommands */
  134. static struct cmds IPcpcmds[] = {
  135.     "close",    doppp_close,    0,    0,    NULLCHAR,
  136.     "listen",    doppp_passive,    0,    0,    NULLCHAR,
  137.     "local",    doipcp_local,    0,    0,    NULLCHAR,
  138.     "open",        doipcp_open,    0,    0,    NULLCHAR,
  139.     "pool",        doipcp_pool,    0,    0,    NULLCHAR,
  140.     "remote",    doipcp_remote,    0,    0,    NULLCHAR,
  141.     "timeout",    doppp_timeout,    0,    0,    NULLCHAR,
  142.     "try",        doppp_try,    0,    0,    NULLCHAR,
  143.     NULLCHAR,
  144. };
  145.  
  146. /* "ppp <iface> ipcp {local | remote}" subcommands */
  147. static struct cmds IPcpside_cmds[] = {
  148.     "address",    doipcp_address,    0,    0,    NULLCHAR,
  149.     "compress",    doipcp_compress,0,    0,    NULLCHAR,
  150.     "default",    doipcp_default,    0,    0,    NULLCHAR,
  151.     NULLCHAR,
  152. };
  153.  
  154.  
  155. int
  156. doppp_ipcp(argc,argv,p)
  157. int argc;
  158. char *argv[];
  159. void *p;
  160. {
  161.     register struct iface *ifp = p;
  162.     register struct ppp_s *ppp_p = ifp->extension;
  163.  
  164.     ipcp_init(ppp_p);
  165.     return subcmd(IPcpcmds, argc, argv, &(ppp_p->fsm[IPcp]));
  166. }
  167.  
  168.  
  169. static int
  170. doipcp_local(argc,argv,p)
  171. int argc;
  172. char *argv[];
  173. void *p;
  174. {
  175.     struct fsm_s *fsm_p = p;
  176.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  177.     return subcmd(IPcpside_cmds, argc, argv, &(ipcp_p->local));
  178. }
  179.  
  180.  
  181. static int
  182. doipcp_open(argc,argv,p)
  183. int argc;
  184. char *argv[];
  185. void *p;
  186. {
  187.     struct fsm_s *fsm_p = p;
  188.  
  189.     doppp_active( argc, argv, p );
  190.  
  191.     if ( fsm_p->ppp_p->phase == pppREADY ) {
  192.         fsm_start( fsm_p );
  193.     }
  194.     return 0;
  195. }
  196.  
  197.  
  198. /* Set a pool of peer addresses for PPP interface */
  199. static int
  200. doipcp_pool(argc,argv,p)
  201. int argc;
  202. char *argv[];
  203. void *p;
  204. {
  205.     struct fsm_s *fsm_p = p;
  206.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  207.     int32 pool_addr;
  208.     int pool_cnt;
  209.  
  210.     if (argc < 2) {
  211.         if ( ipcp_p->peer_min == 0L ) {
  212.             tprintf("None");
  213.         } else {
  214.             tprintf("%s thru ", inet_ntoa(ipcp_p->peer_min));
  215.             tprintf("%s\n", inet_ntoa(ipcp_p->peer_max));
  216.         }
  217.         return 0;
  218.     }
  219.  
  220.     if ((pool_addr = resolve(argv[1])) == 0L) {
  221.         tprintf(Badhost,argv[1]);
  222.     }
  223.  
  224.     /* May specify a consecutive range of addresses; otherwise assume 1 */
  225.     if (argc < 3)
  226.         pool_cnt = 1;
  227.     else
  228.         pool_cnt = (int)strtol( argv[2], NULLCHARP, 0 );
  229.  
  230.     if (pool_cnt <= 0) {
  231.         tprintf("Pool count %s (%d) must be > 0\n");
  232.         return -1;
  233.     }
  234.  
  235.     ipcp_p->peer_min = pool_addr;
  236.     ipcp_p->peer_max = pool_addr + pool_cnt - 1;
  237.     return 0;
  238. }
  239.  
  240.  
  241. static int
  242. doipcp_remote(argc,argv,p)
  243. int argc;
  244. char *argv[];
  245. void *p;
  246. {
  247.     struct fsm_s *fsm_p = p;
  248.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  249.     return subcmd(IPcpside_cmds, argc, argv, &(ipcp_p->remote));
  250. }
  251.  
  252.  
  253. /************************************************************************/
  254. /* Set addresses for PPP interface */
  255. static int
  256. doipcp_address(argc,argv,p)
  257. int argc;
  258. char *argv[];
  259. void *p;
  260. {
  261.     struct ipcp_side_s *side_p = p;
  262.     int32 x32;
  263.  
  264.     if (argc < 2) {
  265.         tprintf("%s\n", inet_ntoa(side_p->want.address));
  266.         return 0;
  267.     } else if ( stricmp(argv[1],"allow") == 0 ) {
  268.         return bit16cmd( &(side_p->will_negotiate), IPCP_N_ADDRESS,
  269.             "Allow Address", --argc, &argv[1] );
  270.     }
  271.     if ((x32 = resolve(argv[1])) == 0L) {
  272.         tprintf(Badhost,argv[1]);
  273.     }
  274.     side_p->want.address = x32;
  275.     side_p->want.negotiate |= IPCP_N_ADDRESS;
  276.     return 0;
  277. }
  278.  
  279.  
  280. /* Set IP compression type for PPP interface */
  281. static int
  282. doipcp_compress(argc,argv,p)
  283. int argc;
  284. char *argv[];
  285. void *p;
  286. {
  287.     struct ipcp_side_s *side_p = p;
  288.  
  289.     if (argc < 2) {
  290.         if ( side_p->want.negotiate & IPCP_N_COMPRESS ) {
  291.             switch ( side_p->want.compression ) {
  292.             case PPP_COMPR_PROTOCOL:
  293.                 tprintf("TCP header compression enabled; "
  294.                     "Slots = %d, slot compress = %x\n",
  295.                     side_p->want.slots,
  296.                     side_p->want.slot_compress);
  297.                 break;
  298.             default:
  299.                 tprintf("0x%04x\n", side_p->want.compression);
  300.                 break;
  301.             };
  302.         } else {
  303.             tprintf("None\n");
  304.         }
  305.     } else if ( stricmp(argv[1],"allow") == 0 ) {
  306.         return bit16cmd( &(side_p->will_negotiate), IPCP_N_COMPRESS,
  307.             "Allow Compression", --argc, &argv[1] );
  308.     } else if ( stricmp(argv[1],"tcp") == 0
  309.          || stricmp(argv[1],"vj") == 0 ) {
  310.         side_p->want.compression = PPP_COMPR_PROTOCOL;
  311.         if ( argc >= 3 ) {
  312.             side_p->want.slots = strtol(argv[2],NULLCHARP,0);
  313.             if ( side_p->want.slots < 1 || side_p->want.slots > 255 ) {
  314.                 tprintf( "slots must be in range 1 to 255" );
  315.                 return 1;
  316.             }
  317.         } else {
  318.             side_p->want.slots = IPCP_SLOT_DEFAULT;
  319.         }
  320.         if ( argc >= 4 ) {
  321.             side_p->want.slot_compress = strtol(argv[3],NULLCHARP,0);
  322.         } else {
  323.             side_p->want.slot_compress = IPCP_SLOT_COMPRESS;
  324.         }
  325.         side_p->want.negotiate |= IPCP_N_COMPRESS;
  326.     } else if (stricmp(argv[1],"none") == 0) {
  327.         side_p->want.negotiate &= ~IPCP_N_COMPRESS;
  328.     } else {
  329.         tprintf("allow tcp none\n");
  330.         return 1;
  331.     }
  332.     return 0;
  333. }
  334.  
  335.  
  336. static int
  337. doipcp_default(argc,argv,p)
  338. int argc;
  339. char *argv[];
  340. void *p;
  341. {
  342.     struct ipcp_side_s *side_p = p;
  343.  
  344.     ASSIGN( side_p->want, ipcp_default );
  345.     return 0;
  346. }
  347.  
  348.  
  349. /************************************************************************/
  350. /*            E V E N T   P R O C E S S I N G            */
  351. /************************************************************************/
  352.  
  353. static void
  354. ipcp_option( bpp, value_p, o_type, o_length, copy_bpp )
  355. struct mbuf **bpp;
  356. struct ipcp_value_s *value_p;
  357. byte_t o_type;
  358. byte_t o_length;
  359. struct mbuf **copy_bpp;
  360. {
  361.     struct mbuf *bp;
  362.     register char *cp;
  363.     register int toss = o_length - OPTION_HDR_LEN;
  364.  
  365.     if ((bp = alloc_mbuf(o_length)) == NULLBUF) {
  366.         return;
  367.     }
  368.     cp = bp->data;
  369.     *cp++ = o_type;
  370.     *cp++ = o_length;
  371.  
  372.     switch ( o_type ) {
  373.     case IPCP_ADDRESS:
  374.         cp = put32(cp, value_p->address);
  375.         cp = put32(cp, value_p->other);
  376.         toss -= 8;
  377. #ifdef PPP_DEBUG_OPTIONS
  378. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  379.     log(-1, "    making IP source address: %s",
  380.         inet_ntoa(value_p->address));
  381.     log(-1, "    making IP destination address %s",
  382.         inet_ntoa(value_p->other));
  383. }
  384. #endif
  385.         break;
  386.  
  387.     case IPCP_COMPRESS:
  388.         cp = put16(cp, value_p->compression);
  389.         toss -= 2;
  390. #ifdef PPP_DEBUG_OPTIONS
  391. if (PPPtrace & PPP_DEBUG_OPTIONS)
  392.     log(-1, "    making IP compression 0x%04x",
  393.         value_p->compression);
  394. #endif
  395.         if ( value_p->compression == PPP_COMPR_PROTOCOL ) {
  396.             *cp++ = value_p->slots - 1;
  397.             *cp++ = value_p->slot_compress;
  398.             toss -= 2;
  399. #ifdef PPP_DEBUG_OPTIONS
  400. if (PPPtrace & PPP_DEBUG_OPTIONS)
  401.     log(-1, "    with IP compression slots %d, flag %x",
  402.         value_p->slots,
  403.         value_p->slot_compress);
  404. #endif
  405.         }
  406.         break;
  407.  
  408.     default:
  409. #ifdef PPP_DEBUG_OPTIONS
  410. if (PPPtrace & PPP_DEBUG_OPTIONS)
  411.     log(-1, "    making unimplemented type %d", o_type);
  412. #endif
  413.         break;
  414.     };
  415.  
  416.     while ( toss-- > 0 ) {
  417.         *cp++ = pullchar(copy_bpp);
  418.     }
  419.     bp->cnt += o_length;
  420.     append(bpp, bp);
  421. }
  422.  
  423.  
  424. /************************************************************************/
  425. /* Build a list of options */
  426. static void
  427. ipcp_makeoptions(bpp, value_p, negotiating)
  428. struct mbuf **bpp;
  429. struct ipcp_value_s *value_p;
  430. int16 negotiating;
  431. {
  432.     register int o_type;
  433.  
  434.     PPP_DEBUG_ROUTINES("ipcp_makeoptions()");
  435.  
  436.     for ( o_type = 1; o_type <= IPCP_OPTION_LIMIT; o_type++ ) {
  437.         if (negotiating & (1 << o_type)) {
  438.             ipcp_option( bpp, value_p,
  439.                 o_type, option_length[ o_type ], NULLBUFP);
  440.         }
  441.     }
  442. }
  443.  
  444.  
  445. /************************************************************************/
  446. /* Build a request to send to remote host */
  447. static struct mbuf *
  448. ipcp_makereq(fsm_p)
  449. struct fsm_s *fsm_p;
  450. {
  451.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  452.     struct mbuf *req_bp = NULLBUF;
  453.  
  454.     PPP_DEBUG_ROUTINES("ipcp_makereq()");
  455.  
  456.     ipcp_makeoptions( &req_bp, &(ipcp_p->local.work),
  457.                 ipcp_p->local.work.negotiate );
  458.     return(req_bp);
  459. }
  460.  
  461.  
  462. /************************************************************************/
  463. /* Check the options, updating the working values.
  464.  * Returns -1 if ran out of data, ACK/NAK/REJ as appropriate.
  465.  */
  466. static int
  467. ipcp_check( bpp, ipcp_p, side_p, option_p, request )
  468. struct mbuf **bpp;
  469. struct ipcp_s *ipcp_p;
  470. struct ipcp_side_s *side_p;
  471. struct option_hdr *option_p;
  472. int request;
  473. {
  474.     int toss = option_p->len - OPTION_HDR_LEN;
  475.     int option_result = CONFIG_ACK;        /* Assume good values */
  476.     int test;
  477.  
  478.     switch(option_p->type) {
  479.     case IPCP_ADDRESS:
  480.         side_p->work.address = pull32(bpp);
  481.         side_p->work.other = pull32(bpp);
  482.         toss -= 8;
  483. #ifdef PPP_DEBUG_OPTIONS
  484. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  485.     log(-1, "    checking IP source address: %s",
  486.         inet_ntoa(side_p->work.address));
  487.     log(-1, "    checking IP destination address %s",
  488.         inet_ntoa(side_p->work.other));
  489. }
  490. #endif
  491.         if ( !request ) {
  492.             /* override any undesirable changes */
  493.             if (ipcp_p->remote.want.address != 0L) {
  494.                 ipcp_p->local.work.other
  495.                     = ipcp_p->remote.want.address;
  496.             }
  497.             if (ipcp_p->local.want.address != 0L) {
  498.                 ipcp_p->local.work.address
  499.                     = ipcp_p->local.want.address;
  500.             }
  501.             break;
  502.         }
  503.  
  504.         /* Ensure that addresses match */
  505.         if (ipcp_p->remote.work.address == ipcp_p->remote.want.address) {
  506.             if (ipcp_p->remote.want.address == 0L) {
  507.                 /* don't know address either */
  508.                 option_result = CONFIG_REJ;
  509.             }
  510.         } else if (ipcp_p->remote.want.address == 0L) {
  511.             ipcp_p->local.work.other = ipcp_p->remote.work.address;
  512.         } else {
  513.             ipcp_p->remote.work.address = ipcp_p->remote.want.address;
  514.             option_result = CONFIG_NAK;
  515.         }
  516.  
  517.         if (ipcp_p->remote.work.other == ipcp_p->local.want.address) {
  518.             if (ipcp_p->local.want.address == 0L) {
  519.                 /* don't know address either */
  520.                 option_result = CONFIG_REJ;
  521.             }
  522.         } else if (ipcp_p->local.want.address == 0L) {
  523.             ipcp_p->local.work.address = ipcp_p->remote.work.other;
  524.         } else {
  525.             option_result = CONFIG_NAK;
  526.             ipcp_p->remote.work.other = ipcp_p->local.want.address;
  527.         }
  528.         break;
  529.  
  530.     case IPCP_COMPRESS:
  531.         side_p->work.compression = pull16(bpp);
  532.         toss -= 2;
  533. #ifdef PPP_DEBUG_OPTIONS
  534. if (PPPtrace & PPP_DEBUG_OPTIONS)
  535.     log(-1, "    checking IP compression 0x%04x",
  536.         side_p->work.compression);
  537. #endif
  538.         /* Check if requested type is acceptable */
  539.         switch ( side_p->work.compression ) {
  540.         case PPP_COMPR_PROTOCOL:
  541.             if ( (test = pullchar(bpp)) == -1 ) {
  542.                 return -1;
  543.             }
  544.             if ( (side_p->work.slots = test + 1) < IPCP_SLOT_LO) {
  545.                 side_p->work.slots = IPCP_SLOT_LO;
  546.                 option_result = CONFIG_NAK;
  547.             } else if (side_p->work.slots > IPCP_SLOT_HI) {
  548.                 side_p->work.slots = IPCP_SLOT_HI;
  549.                 option_result = CONFIG_NAK;
  550.             }
  551.  
  552.             if ( (test = pullchar(bpp)) == -1 ) {
  553.                 return -1;
  554.             }
  555.             if ( (side_p->work.slot_compress = test) > 1 ) {
  556.                 side_p->work.slot_compress = 1;
  557.                 option_result = CONFIG_NAK;
  558.             }
  559.             toss -= 2;
  560. #ifdef PPP_DEBUG_OPTIONS
  561. if (PPPtrace & PPP_DEBUG_OPTIONS)
  562.     log(-1, "    with IP compression slots %d, flag %x",
  563.         side_p->work.slots,
  564.         side_p->work.slot_compress);
  565. #endif
  566.             break;
  567.  
  568.         default:
  569.             if ( side_p->want.negotiate & IPCP_N_COMPRESS ) {
  570.                 side_p->work.compression = side_p->want.compression;
  571.                 side_p->work.slots = side_p->want.slots;
  572.                 side_p->work.slot_compress = side_p->want.slot_compress;
  573.             } else {
  574.                 side_p->work.compression = PPP_COMPR_PROTOCOL;
  575.                 side_p->work.slots = IPCP_SLOT_DEFAULT;
  576.                 side_p->work.slot_compress = IPCP_SLOT_COMPRESS;
  577.             }
  578.             option_result = CONFIG_NAK;
  579.             break;
  580.         };
  581.         break;
  582.  
  583.     default:
  584.         option_result = CONFIG_REJ;
  585.         break;
  586.     };
  587.  
  588.     if (option_p->type > IPCP_OPTION_LIMIT
  589.      || !(side_p->will_negotiate & (1 << option_p->type))) {
  590.         option_result = CONFIG_REJ;
  591.     }
  592.  
  593.     if ( toss < 0 )
  594.         return -1;
  595.  
  596.     if ( !request  &&  toss > 0 ) {
  597.         /* toss extra bytes in option */
  598.         while( toss-- > 0 ) {
  599.             if ( pullchar(bpp) == -1 )
  600.                 return -1;
  601.         }
  602.     }
  603.  
  604.     return (option_result);
  605. }
  606.  
  607.  
  608. /************************************************************************/
  609. /* Check options requested by the remote host */
  610. static int
  611. ipcp_request(fsm_p, config, data)
  612. struct fsm_s *fsm_p;
  613. struct config_hdr *config;
  614. struct mbuf *data;
  615. {
  616.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  617.     int32 signed_length = config->len;
  618.     struct mbuf *reply_bp = NULLBUF;    /* reply packet */
  619.     int reply_result = CONFIG_ACK;        /* reply to request */
  620.     int16 desired;                /* desired to negotiate */
  621.     struct option_hdr option;        /* option header storage */
  622.     int option_result;            /* option reply */
  623.  
  624.     PPP_DEBUG_ROUTINES("ipcp_request()");
  625.     ipcp_p->remote.work.negotiate = FALSE;    /* clear flags */
  626.  
  627.     /* Process options requested by remote host */
  628.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  629.         if ((signed_length -= option.len) < 0) {
  630.             PPP_DEBUG_CHECKS("IPCP REQ: bad header length");
  631.             free_p(data);
  632.             free_p(reply_bp);
  633.             return -1;
  634.         }
  635.  
  636.         if ( ( option_result = ipcp_check( &data, ipcp_p,
  637.                 &(ipcp_p->remote), &option, TRUE ) ) == -1 ) {
  638.             PPP_DEBUG_CHECKS("IPCP REQ: ran out of data");
  639.             free_p(data);
  640.             free_p(reply_bp);
  641.             return -1;
  642.         }
  643.  
  644. #ifdef PPP_DEBUG_OPTIONS
  645. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  646.     log(-1, "IPCP REQ: result %s, option %d, length %d",
  647.         fsmCodes[option_result],
  648.         option.type,
  649.         option.len);
  650. }
  651. #endif
  652.         if ( option_result < reply_result ) {
  653.             continue;
  654.         } else if ( option_result > reply_result ) {
  655.             /* Discard current list of replies */
  656.             free_p(reply_bp);
  657.             reply_bp = NULLBUF;
  658.             reply_result = option_result;
  659.         }
  660.  
  661.         /* remember that we processed option */
  662.         if ( option_result != CONFIG_REJ
  663.          && option.type <= IPCP_OPTION_LIMIT ) {
  664.             ipcp_p->remote.work.negotiate |= (1 << option.type);
  665.         }
  666.  
  667.         /* Add option response to the return list */
  668.         ipcp_option( &reply_bp, &(ipcp_p->remote.work),
  669.             option.type, option.len, &data );
  670.     }
  671.  
  672.     /* Now check for any missing options which are desired */
  673.     if ( fsm_p->retry_nak > 0
  674.      &&  (desired = ipcp_p->remote.want.negotiate
  675.                & ~ipcp_p->remote.work.negotiate) != 0 ) {
  676.         switch ( reply_result ) {
  677.         case CONFIG_ACK:
  678.             free_p(reply_bp);
  679.             reply_bp = NULLBUF;
  680.             reply_result = CONFIG_NAK;
  681.             /* fallthru */
  682.         case CONFIG_NAK:
  683.             ipcp_makeoptions( &reply_bp, &(ipcp_p->remote.want),
  684.                 desired );
  685.             fsm_p->retry_nak--;
  686.             break;
  687.         case CONFIG_REJ:
  688.             /* do nothing */
  689.             break;
  690.         };
  691.     } else if ( reply_result == CONFIG_NAK ) {
  692.         /* if too many NAKs, reject instead */
  693.         if ( fsm_p->retry_nak > 0 )
  694.             fsm_p->retry_nak--;
  695.         else
  696.             reply_result = CONFIG_REJ;
  697.     }
  698.  
  699.     /* Send ACK/NAK/REJ to remote host */
  700.     fsm_send(fsm_p, reply_result, config->id, reply_bp);
  701.     free_p(data);
  702.     return (reply_result != CONFIG_ACK);
  703. }
  704.  
  705.  
  706. /************************************************************************/
  707. /* Process configuration ACK sent by remote host */
  708. static int
  709. ipcp_ack(fsm_p, config, data)
  710. struct fsm_s *fsm_p;
  711. struct config_hdr *config;
  712. struct mbuf *data;
  713. {
  714.     struct mbuf *req_bp;
  715.     int error = FALSE;
  716.  
  717.     PPP_DEBUG_ROUTINES("ipcp_ack()");
  718.  
  719.     /* ID field must match last request we sent */
  720.     if (config->id != fsm_p->lastid) {
  721.         PPP_DEBUG_CHECKS("IPCP ACK: wrong ID");
  722.         free_p(data);
  723.         return -1;
  724.     }
  725.  
  726.     /* Get a copy of last request we sent */
  727.     req_bp = ipcp_makereq(fsm_p);
  728.  
  729.     /* Overall buffer length should match */
  730.     if (config->len != len_p(req_bp)) {
  731.         PPP_DEBUG_CHECKS("IPCP ACK: buffer length mismatch");
  732.         error = TRUE;
  733.     } else {
  734.         register int req_char;
  735.         register int ack_char;
  736.  
  737.         /* Each byte should match */
  738.         while ((req_char = pullchar(&req_bp)) != -1) {
  739.             if ((ack_char = pullchar(&data)) == -1
  740.              || ack_char != req_char ) {
  741.                 PPP_DEBUG_CHECKS("IPCP ACK: data mismatch");
  742.                 error = TRUE;
  743.                 break;
  744.             }
  745.         }
  746.     }
  747.     free_p(req_bp);
  748.     free_p(data);
  749.  
  750.     if (error) {
  751.         return -1;
  752.     }
  753.  
  754.     PPP_DEBUG_CHECKS("IPCP ACK: valid");
  755.     return 0;
  756. }
  757.  
  758.  
  759. /************************************************************************/
  760. /* Process configuration NAK sent by remote host */
  761. static int
  762. ipcp_nak(fsm_p, config, data)
  763. struct fsm_s *fsm_p;
  764. struct config_hdr *config;
  765. struct mbuf *data;
  766. {
  767.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  768.     struct ipcp_side_s *local_p = &(ipcp_p->local);
  769.     int32 signed_length = config->len;
  770.     struct option_hdr option;
  771.     int last_option = 0;
  772.     int result;
  773.  
  774.     PPP_DEBUG_ROUTINES("ipcp_nak()");
  775.  
  776.     /* ID field must match last request we sent */
  777.     if (config->id != fsm_p->lastid) {
  778.         PPP_DEBUG_CHECKS("IPCP NAK: wrong ID");
  779.         free_p(data);
  780.         return -1;
  781.     }
  782.  
  783.     /* First, process in order.  Then, process extra "important" options */
  784.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  785.         if ((signed_length -= option.len) < 0) {
  786.             PPP_DEBUG_CHECKS("IPCP NAK: bad header length");
  787.             free_p(data);
  788.             return -1;
  789.         }
  790.         if ( option.type > IPCP_OPTION_LIMIT ) {
  791.             PPP_DEBUG_CHECKS("IPCP NAK: option out of range");
  792.         } else if ( option.type < last_option
  793.          || !(local_p->work.negotiate & (1 << option.type)) ) {
  794.             if (local_p->work.negotiate & (1 << option.type)) {
  795.                 PPP_DEBUG_CHECKS("IPCP NAK: option out of order");
  796.                 free_p(data);
  797.                 return -1;        /* was requested */
  798.             }
  799.             local_p->work.negotiate |= (1 << option.type);
  800.             last_option = IPCP_OPTION_LIMIT + 1;
  801.         } else {
  802.             last_option = option.type;
  803.         }
  804.         if ( ( result = ipcp_check( &data, ipcp_p,
  805.                 local_p, &option, FALSE ) ) == -1 ) {
  806.             PPP_DEBUG_CHECKS("IPCP NAK: ran out of data");
  807.             free_p(data);
  808.             return -1;
  809.         }
  810.         /* update the negotiation status */
  811.         if ( result == CONFIG_REJ
  812.           && option.type <= IPCP_OPTION_LIMIT ) {
  813.             local_p->work.negotiate &= ~(1 << option.type);
  814.         }
  815.     }
  816.     PPP_DEBUG_CHECKS("IPCP NAK: valid");
  817.     free_p(data);
  818.     return 0;
  819. }
  820.  
  821.  
  822. /************************************************************************/
  823. /* Process configuration reject sent by remote host */
  824. static int
  825. ipcp_reject(fsm_p, config, data)
  826. struct fsm_s *fsm_p;
  827. struct config_hdr *config;
  828. struct mbuf *data;
  829. {
  830.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  831.     struct ipcp_side_s *local_p = &(ipcp_p->local);
  832.     int32 signed_length = config->len;
  833.     struct option_hdr option;
  834.     int last_option = 0;
  835.  
  836.     PPP_DEBUG_ROUTINES("ipcp_reject()");
  837.  
  838.     /* ID field must match last request we sent */
  839.     if (config->id != fsm_p->lastid) {
  840.         PPP_DEBUG_CHECKS("IPCP REJ: wrong ID");
  841.         free_p(data);
  842.         return -1;
  843.     }
  844.  
  845.     /* Process in order, checking for errors */
  846.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  847.         register int k;
  848.  
  849.         if ((signed_length -= option.len) < 0) {
  850.             PPP_DEBUG_CHECKS("IPCP REJ: bad header length");
  851.             free_p(data);
  852.             return -1;
  853.         }
  854.         if ( option.type > IPCP_OPTION_LIMIT ) {
  855.             PPP_DEBUG_CHECKS("IPCP REJ: option out of range");
  856.         } else if (option.type < last_option
  857.          || !(local_p->work.negotiate & (1 << option.type))) {
  858.             PPP_DEBUG_CHECKS("IPCP REJ: option out of order");
  859.             free_p(data);
  860.             return -1;
  861.         }
  862.         for ( k = option.len - OPTION_HDR_LEN; k-- > 0; ) {
  863.             if ( pullchar(&data) == -1 ) {
  864.                 PPP_DEBUG_CHECKS("IPCP REJ: ran out of data");
  865.                 free_p(data);
  866.                 return -1;
  867.             }
  868.         }
  869.         last_option = option.type;
  870.  
  871.         if ( option.type <= IPCP_OPTION_LIMIT ) {
  872.             local_p->work.negotiate &= ~(1 << option.type);
  873.         }
  874.     }
  875.     PPP_DEBUG_CHECKS("IPCP REJ: valid");
  876.     free_p(data);
  877.     return 0;
  878. }
  879.  
  880.  
  881. /************************************************************************/
  882. /*            I N I T I A L I Z A T I O N            */
  883. /************************************************************************/
  884.  
  885. /* Reset configuration options before request */
  886. static void
  887. ipcp_reset(fsm_p)
  888. struct fsm_s *fsm_p;
  889. {
  890.     struct ipcp_s *ipcp_p =    fsm_p->pdv;
  891.  
  892.     PPP_DEBUG_ROUTINES("ipcp_reset()");
  893.  
  894.     ASSIGN( ipcp_p->local.work, ipcp_p->local.want );
  895.     ipcp_p->local.work.other = ipcp_p->remote.want.address;
  896.     ipcp_p->local.will_negotiate |= ipcp_p->local.want.negotiate;
  897.  
  898.     ipcp_p->remote.work.negotiate = FALSE;
  899.     ipcp_p->remote.will_negotiate |= ipcp_p->remote.want.negotiate;
  900. }
  901.  
  902.  
  903. /************************************************************************/
  904. static int32
  905. ipcp_addr_idle(addr)
  906. int32 addr;
  907. {
  908.     struct iface *ifp;
  909.  
  910.     /* Check if peer IP address is already in use on another interface */
  911.     for (ifp=Ifaces; ifp != NULLIF; ifp = ifp->next) {
  912.         if (ifp->addr == addr)
  913.             return 0L;
  914.     }
  915.     return addr;
  916. }
  917.  
  918.  
  919. /************************************************************************/
  920. static int32
  921. ipcp_poolnext(ipcp_p)
  922. struct ipcp_s *ipcp_p;
  923. {
  924.     int32 i = 1L + ipcp_p->peer_max - ipcp_p->peer_min;
  925.     int32 nextaddr = 0L;
  926.  
  927.     while ( i-- > 0  &&  nextaddr == 0L ) {
  928.         if (++ipcp_p->local.want.other < ipcp_p->peer_min
  929.          || ipcp_p->local.want.other > ipcp_p->peer_max)
  930.             ipcp_p->local.want.other = ipcp_p->peer_min;
  931.  
  932.         nextaddr = ipcp_addr_idle(ipcp_p->local.want.other);
  933.     }
  934.     return(nextaddr);
  935. }
  936.  
  937.  
  938. /************************************************************************/
  939. /* Check if we have a specific IP address to assign to remote peer host */
  940. static int32
  941. ipcp_lookuppeer(peerid)
  942. char *peerid;
  943. {
  944.     char *buf;
  945.     int32 peer_addr = 0L;
  946.  
  947.     if (peerid == NULLCHAR)
  948.         return 0L;
  949.  
  950.     if ( (buf = userlookup( peerid, NULLCHARP, NULLCHARP,
  951.             NULL, &peer_addr )) != NULLCHAR ) {
  952.         free(buf);
  953.     }
  954.     return(peer_addr);
  955. }
  956.  
  957.  
  958. /************************************************************************/
  959. /* Prepare to begin configuration exchange */
  960. static void
  961. ipcp_starting(fsm_p)
  962. struct fsm_s *fsm_p;
  963. {
  964.     struct lcp_s *lcp_p =         fsm_p->ppp_p->fsm[Lcp].pdv;
  965.     struct pap_s *pap_p =         fsm_p->ppp_p->fsm[Pap].pdv;
  966.     struct ipcp_s *ipcp_p =        fsm_p->pdv;
  967.  
  968.     PPP_DEBUG_ROUTINES("ipcp_starting()");
  969.  
  970.     /* If not already set, and we required authentication,
  971.      * look in FTPUSER file
  972.      */
  973.     if ((ipcp_p->remote.want.address == 0L)
  974.      && (lcp_p->local.want.negotiate & LCP_N_AUTHENT)) {
  975.         ipcp_p->remote.want.address = ipcp_lookuppeer(pap_p->peername);
  976.     }
  977.  
  978.     /* If used, get next address from PPP pool */
  979.     if ((ipcp_p->remote.want.address == 0L)
  980.      && (ipcp_p->peer_min != 0L)) {
  981.         ipcp_p->remote.want.address = ipcp_poolnext(ipcp_p);
  982.     }
  983. }
  984.  
  985.  
  986. /************************************************************************/
  987. /* After termination */
  988. static void
  989. ipcp_stopping(fsm_p)
  990. struct fsm_s *fsm_p;
  991. {
  992.     PPP_DEBUG_ROUTINES("ipcp_stopping()");
  993. }
  994.  
  995.  
  996. /************************************************************************/
  997. /* Close IPCP */
  998. static void
  999. ipcp_closing(fsm_p)
  1000. struct fsm_s *fsm_p;
  1001. {
  1002.     struct ipcp_s *ipcp_p =     fsm_p->pdv;
  1003.     struct iface *ifp =         fsm_p->ppp_p->iface;
  1004.  
  1005.     if (PPPtrace > 1)
  1006.         log(-1,"%s: PPP/IPCP Drop route to peer (%s)",
  1007.             ifp->name,
  1008.             inet_ntoa(ipcp_p->local.work.other));
  1009.  
  1010.     rt_drop(ipcp_p->local.work.other, (unsigned int)32);
  1011. }
  1012.  
  1013.  
  1014. /************************************************************************/
  1015. /* configuration negotiation complete */
  1016. static void
  1017. ipcp_opening(fsm_p)
  1018. struct fsm_s *fsm_p;
  1019. {
  1020.     struct ipcp_s *ipcp_p =     fsm_p->pdv;
  1021.     struct iface *ifp =         fsm_p->ppp_p->iface;
  1022.     int rslots = 0;
  1023.     int tslots = 0;
  1024.  
  1025.     /* Set our IP address to reflect negotiated option */
  1026.     if (ipcp_p->local.work.address != ifp->addr) {
  1027.         if (Ip_addr == 0L) {
  1028.             Ip_addr = ipcp_p->local.work.address;
  1029.         } else if ( Ip_addr == ifp->addr ) {
  1030.             /* We just are not what we used to be (sigh) */
  1031.             /* Quash anyone who thinks otherwise */
  1032.             ipcp_closing(fsm_p);
  1033.             Ip_addr = ipcp_p->local.work.address;
  1034.         }
  1035.         ifp->addr = ipcp_p->local.work.address;
  1036.  
  1037.         if (PPPtrace > 1)
  1038.             log(-1,"%s: PPP/IPCP Saving new IP addr: %s",
  1039.                 ifp->name,
  1040.                 inet_ntoa(ipcp_p->local.work.address));
  1041.     }
  1042.  
  1043.     rt_add(ipcp_p->local.work.other, (unsigned int)32, (int32)0,
  1044.         ifp, (int32)1, (int32)0, (char)1);
  1045.  
  1046.     if (PPPtrace > 1)
  1047.         log(-1,"%s: PPP/IPCP Add route to peer (%s)",
  1048.             ifp->name,
  1049.             inet_ntoa(ipcp_p->local.work.other));
  1050.  
  1051.     /* free old slhc configuration, if any */
  1052.     slhc_free( ipcp_p->slhcp );
  1053.  
  1054.     if (ipcp_p->local.work.negotiate & IPCP_N_COMPRESS) {
  1055.         rslots = ipcp_p->local.work.slots;
  1056.     }
  1057.     if (ipcp_p->remote.work.negotiate & IPCP_N_COMPRESS) {
  1058.         tslots = ipcp_p->remote.work.slots;
  1059.     }
  1060.  
  1061.     if ( rslots != 0 || tslots != 0 ) {
  1062.         ipcp_p->slhcp = slhc_init( rslots, tslots );
  1063.  
  1064.         if (PPPtrace > 1)
  1065.             log(-1,"%s: PPP/IPCP Compression enabled;"
  1066.                 " Recv slots = %d, flag = %x;"
  1067.                 " Xmit slots = %d, flag = %x",
  1068.                 ifp->name,
  1069.                 rslots,
  1070.                 ipcp_p->local.work.slot_compress,
  1071.                 tslots,
  1072.                 ipcp_p->remote.work.slot_compress);
  1073.     }
  1074. }
  1075.  
  1076.  
  1077. /************************************************************************/
  1078. static void
  1079. ipcp_free(fsm_p)
  1080. struct fsm_s *fsm_p;
  1081. {
  1082.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  1083.  
  1084.     slhc_free( ipcp_p->slhcp );
  1085. }
  1086.  
  1087.  
  1088. /* Initialize configuration structure */
  1089. static void
  1090. ipcp_init(ppp_p)
  1091. struct ppp_s *ppp_p;
  1092. {
  1093.     struct fsm_s *fsm_p;
  1094.     struct ipcp_s *ipcp_p;
  1095.  
  1096.     PPPtrace = ppp_p->trace;
  1097.  
  1098.     PPP_DEBUG_ROUTINES("ipcp_init()");
  1099.  
  1100.     if (ppp_p->fsm[IPcp].pdv != NULL)
  1101.         return;        /* already initialized */
  1102.  
  1103.     fsm_p = &(ppp_p->fsm[IPcp]);
  1104.     fsm_p->ppp_p = ppp_p;
  1105.     fsm_p->pdc = &ipcp_constants;
  1106.     fsm_p->pdv =
  1107.     ipcp_p = callocw(1,sizeof(struct ipcp_s));
  1108.  
  1109.     /* Set option parameters to first request defaults */
  1110.     ASSIGN( ipcp_p->local.want, ipcp_default );
  1111.     ipcp_p->local.will_negotiate = ipcp_negotiate;
  1112.  
  1113.     ASSIGN( ipcp_p->remote.want, ipcp_default );
  1114.     ASSIGN( ipcp_p->remote.work, ipcp_default);
  1115.     ipcp_p->remote.will_negotiate = ipcp_negotiate;
  1116.  
  1117.     fsm_init(fsm_p);
  1118. }
  1119.  
  1120.  
  1121.